import java.util.HashMap;
import java.util.ArrayList;

public class Student extends Person
{
    private String department, speciality, number;
    private boolean member;
    private int grade, classId;
    private HashMap<String,Double> score;
    private static int count=0;

    private static HashMap<String,Integer> departmentMap=new HashMap<String,Integer>();    //存院编号
    private static HashMap<String,HashMap<String,Integer>> specialityMap=new HashMap<String,HashMap<String,Integer>>();  //存系编号
    private static HashMap<String,HashMap<String,HashMap<Integer,Integer>>> specialityCount=new HashMap<String,HashMap<String,HashMap<Integer,Integer>>>();  //存系里哪一年级有几个人

    private String generateNumber(int grade,String department,String speciality)
    {
        String number=String.format("%04d",grade);
        if(!departmentMap.containsKey(department))
        {
            departmentMap.put(department,departmentMap.size()+1);
            specialityMap.put(department,new HashMap<String,Integer>());
            specialityCount.put(department,new HashMap<String,HashMap<Integer,Integer>>());
        }
        number+=String.format("%02d",departmentMap.get(department));
        if(!specialityMap.get(department)
                         .containsKey(speciality))
        {
            HashMap<String,Integer> spm=specialityMap.get(department);
            HashMap<String,HashMap<Integer,Integer>> spc=specialityCount.get(department);
            spm.put(speciality,spm.size()+1);
            spc.put(speciality,new HashMap<Integer,Integer>());
            specialityMap.replace(department,spm);
            specialityCount.replace(department,spc);
        }
        number+=String.format("%02d",specialityMap.get(department)
                                                  .get(speciality));
        if(!specialityCount.get(department)
                           .get(speciality)
                           .containsKey(grade))
        {
            HashMap<Integer,Integer> spc=specialityCount.get(department)
                                                        .get(speciality);
            spc.put(grade,0);
            specialityCount.get(department)
                           .replace(speciality,spc);
        }
        HashMap<Integer,Integer> spc=specialityCount.get(department)
                                                    .get(speciality);
        spc.replace(grade,spc.get(grade)+1);
        specialityCount.get(department)
                       .replace(speciality,spc);
        number+=String.format("%03d",specialityCount.get(department)
                                                    .get(speciality)
                                                    .get(grade));


        return number;
    }

    public Student(String name,MyDate birthdate,String gender,String province,String city,int grade,String department,String speciality,int classId,boolean member)
    {
        super(name,birthdate,gender,province,city);
        this.set(grade,department,speciality,classId,this.generateNumber(grade,department,speciality),member);
        this.score=new HashMap<String,Double>();
        ++count;
    }

    public Student()
    {
        //需要指出的是,这里有一点奇怪,因为他会自动生成一个年级院系专业都是空的学号。。。。。
        super();
        this.set(0,"","",0,this.generateNumber(0,"",""),false);
        ++count;
    }

    public Student(Person person,int grade,String department,String speciality,int classId,boolean member)
    {
        super(person);
        this.set(grade,department,speciality,classId,this.generateNumber(grade,department,speciality),member);
        ++count;
        this.score=new HashMap<String,Double>();
    }

    public Student(Student stu)
    {
        //需要指出的是,这里并没有按照书上给出的调其他构造函数的方法进行构造,主要是因为我认为这种情况不需要重新分配学号,而上面经过改造的构造函数会自动分配学号
        super(stu);
        this.score=new HashMap<String,Double>(stu.score);
        this.set(stu.grade,stu.department,stu.speciality,stu.classId,stu.number,stu.member);
        ++count;
    }

    public void finalize()
    {
        super.finalize();
        --count;
    }

    public static void howMany()
    {
        Person.howMany();
        System.out.print(count+"个Student对象,");
    }

    public void set(int grade,String department,String speciality,int classId,String number,boolean member)
    {
        this.department=department==null?"":department;
        this.speciality=speciality==null?"":speciality;
        this.number=number==null?"":number;
        this.member=member;
        this.grade=grade;
        this.classId=classId;
    }

    public String toString()
    {
        String s=super.toString()+","+String.format("%04d",this.grade)+","+this.department+","+this.speciality+","+String.format("%02d班",this.classId)+","+this.number+(member?",团员":"");
        if(this.score.size()!=0)
        {
            s+=",score(";
            for(String course: this.score.keySet())
            {
                s+=course+":"+this.score.get(course)+",";
            }
            s+=")";
        }
        return s;
    }

    public void setScore(String course,double score)
    {
        if(!this.score.containsKey(course))
            this.score.put(course,score);
        else
            this.score.replace(course,score);
    }

    public double getScore(String course)
    {
        if(this.score.containsKey(course))
            return this.score.get(course);
        return 0;
    }

    public static HashMap<Integer,HashMap<String,HashMap<String,HashMap<Integer,HashMap<String,Double>>>>> getAverageScore(Student stus[])
    {
        HashMap<Integer,HashMap<String,HashMap<String,HashMap<Integer,HashMap<String,double[]>>>>> score=new HashMap<Integer,HashMap<String,HashMap<String,HashMap<Integer,HashMap<String,double[]>>>>>();//年级 院 系 班 课 [分,人数]
        for(Student stu: stus)
        {
            for(String course: stu.score.keySet())
            {
                if(!score.containsKey(stu.grade))
                    score.put(stu.grade,new HashMap<String,HashMap<String,HashMap<Integer,HashMap<String,double[]>>>>());
                if(!score.get(stu.grade)
                         .containsKey(stu.department))
                    score.get(stu.grade)
                         .put(stu.department,new HashMap<String,HashMap<Integer,HashMap<String,double[]>>>());
                if(!score.get(stu.grade)
                         .get(stu.department)
                         .containsKey(stu.speciality))
                    score.get(stu.grade)
                         .get(stu.department)
                         .put(stu.speciality,new HashMap<Integer,HashMap<String,double[]>>());
                if(!score.get(stu.grade)
                         .get(stu.department)
                         .get(stu.speciality)
                         .containsKey(stu.classId))
                    score.get(stu.grade)
                         .get(stu.department)
                         .get(stu.speciality)
                         .put(stu.classId,new HashMap<String,double[]>());
                if(!score.get(stu.grade)
                         .get(stu.department)
                         .get(stu.speciality)
                         .get(stu.classId)
                         .containsKey(course))
                    score.get(stu.grade)
                         .get(stu.department)
                         .get(stu.speciality)
                         .get(stu.classId)
                         .put(course,new double[2]);
                //这里有点奇怪,他引用了
                double[] grade=score.get(stu.grade)
                                    .get(stu.department)
                                    .get(stu.speciality)
                                    .get(stu.classId)
                                    .get(course);
                grade[0]+=stu.score.get(course);
                ++grade[1];
            }
        }

        HashMap<Integer,HashMap<String,HashMap<String,HashMap<Integer,HashMap<String,Double>>>>> ans=new HashMap<Integer,HashMap<String,HashMap<String,HashMap<Integer,HashMap<String,Double>>>>>();
        for(int grade: score.keySet())
        {
            ans.put(grade,new HashMap<String,HashMap<String,HashMap<Integer,HashMap<String,Double>>>>());
            for(String department: score.get(grade)
                                        .keySet())
            {
                ans.get(grade)
                   .put(department,new HashMap<String,HashMap<Integer,HashMap<String,Double>>>());
                for(String speciality: score.get(grade)
                                            .get(department)
                                            .keySet())
                {
                    ans.get(grade)
                       .get(department)
                       .put(speciality,new HashMap<Integer,HashMap<String,Double>>());
                    for(int classId: score.get(grade)
                                          .get(department)
                                          .get(speciality)
                                          .keySet())
                    {
                        ans.get(grade)
                           .get(department)
                           .get(speciality)
                           .put(classId,new HashMap<String,Double>());

                        for(String course: score.get(grade)
                                                .get(department)
                                                .get(speciality)
                                                .get(classId)
                                                .keySet())
                        {
                            ans.get(grade)
                               .get(department)
                               .get(speciality)
                               .get(classId)
                               .put(course,score.get(grade)
                                                .get(department)
                                                .get(speciality)
                                                .get(classId)
                                                .get(course)[0]/score.get(grade)
                                                                     .get(department)
                                                                     .get(speciality)
                                                                     .get(classId)
                                                                     .get(course)[1]);
                        }
                    }
                }
            }
        }
        return ans;
    }

    public static void printAverageScore(HashMap<Integer,HashMap<String,HashMap<String,HashMap<Integer,HashMap<String,Double>>>>> score)
    {
        for(int grade: score.keySet())
        {
            System.out.println(String.format("%04d级",grade));
            for(String department: score.get(grade)
                                        .keySet())
            {
                System.out.println("|--"+department);
                for(String speciality: score.get(grade)
                                            .get(department)
                                            .keySet())
                {
                    System.out.println("|--|--"+speciality);
                    for(int classId: score.get(grade)
                                          .get(department)
                                          .get(speciality)
                                          .keySet())
                    {
                        System.out.println("|--|--|--"+String.format("%02d班",classId));
                        for(String course: score.get(grade)
                                                .get(department)
                                                .get(speciality)
                                                .get(classId)
                                                .keySet())
                        {
                            System.out.println("|--|--|--|--"+course+":"+String.format("%.2f",score.get(grade)
                                                                                                   .get(department)
                                                                                                   .get(speciality)
                                                                                                   .get(classId)
                                                                                                   .get(course)));
                        }
                    }
                }
            }
        }
    }

    public static void printStudents(Student students[])
    {
        HashMap<Integer,HashMap<String,HashMap<String,HashMap<Integer,ArrayList<Student>>>>> stus=new HashMap<Integer,HashMap<String,HashMap<String,HashMap<Integer,ArrayList<Student>>>>>();//年级 院 系 班 人
        for(Student stu: students)
        {
            if(!stus.containsKey(stu.grade))
                stus.put(stu.grade,new HashMap<String,HashMap<String,HashMap<Integer,ArrayList<Student>>>>());
            if(!stus.get(stu.grade)
                    .containsKey(stu.department))
                stus.get(stu.grade)
                    .put(stu.department,new HashMap<String,HashMap<Integer,ArrayList<Student>>>());
            if(!stus.get(stu.grade)
                    .get(stu.department)
                    .containsKey(stu.speciality))
                stus.get(stu.grade)
                    .get(stu.department)
                    .put(stu.speciality,new HashMap<Integer,ArrayList<Student>>());
            if(!stus.get(stu.grade)
                    .get(stu.department)
                    .get(stu.speciality)
                    .containsKey(stu.classId))
                stus.get(stu.grade)
                    .get(stu.department)
                    .get(stu.speciality)
                    .put(stu.classId,new ArrayList<Student>());
            stus.get(stu.grade)
                .get(stu.department)
                .get(stu.speciality)
                .get(stu.classId)
                .add(new Student(stu));
        }
        for(int grade: stus.keySet())
        {
            System.out.println(String.format("%04d级",grade));
            for(String department: stus.get(grade)
                                       .keySet())
            {
                System.out.println("|--"+department);
                for(String speciality: stus.get(grade)
                                           .get(department)
                                           .keySet())
                {
                    System.out.println("|--|--"+speciality);
                    for(int classId: stus.get(grade)
                                         .get(department)
                                         .get(speciality)
                                         .keySet())
                    {
                        System.out.println("|--|--|--"+String.format("%02d班",classId));
                        for(Student stu: stus.get(grade)
                                             .get(department)
                                             .get(speciality)
                                             .get(classId))
                        {
                            System.out.println("|--|--|--|--"+stu);
                        }
                    }
                }
            }
        }
    }

}
